package org.daochong.web;

import java.io.PrintWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.daochong.lang.BeanUtil;
import org.daochong.lang.StringUtils;

public class WebUtils {
	public static String TOKEN = "token";
	public static final String SP = "@@CRLF@@";

	public static Map<String, String> getRequestMap(HttpServletRequest request) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Enumeration<String> en = request.getParameterNames();
		while (en.hasMoreElements()) {
			String str = en.nextElement();
			map.put(str, request.getParameter(str));
		}
		return map;
	}

	public static String toRequestId(HttpServletRequest request, String... out) {
		StringBuilder sb = new StringBuilder();
		sb.append(request.getContextPath());
		sb.append("/");
		sb.append(request.getRequestURI());
		sb.append("\r\n");
		List<String> list = Collections.list(request.getParameterNames());
		Collections.sort(list);
		for (String p : list) {
			boolean flag = false;
			for (String s : out) {
				if (s.equals(p)) {
					flag = true;
					break;
				}
			}
			if (flag)
				continue;
			sb.append(p + "=" + request.getParameter(p) + "\r\n");
		}
		return StringUtils.md5(sb.toString());
	}

	public static Map<String, String> getRequestMapWithout(HttpServletRequest request, String... ar) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Enumeration<String> en = request.getParameterNames();
		while (en.hasMoreElements()) {
			String str = en.nextElement();
			boolean find = false;
			for (String s : ar) {
				if (str.equals(s)) {
					find = true;
					break;
				}
			}
			if (find) {
				continue;
			}
			map.put(str, request.getParameter(str));
		}
		return map;
	}

	public static String getHost(HttpServletRequest request) {
		return request.getScheme() + "://" + request.getServerName()
				+ (request.getServerPort() == 80 ? "" : ":" + request.getServerPort());
	}

	public static boolean isInside(String ip) {
		if (ip == null)
			return false;
		if (ip.equals("127.0.0.1")) {
			return true;
		} else if (ip.startsWith("192.168.")) {
			return true;
		} else if (ip.startsWith("10.")) {
			return true;
		} else if (ip.startsWith("10.")) {
			return true;
		}
		String[] ar = ip.split("\\.");
		if (ar.length == 4) {
			int i = Integer.parseInt(ar[1]);
			if (ar[0].equals("172") && (i >= 16 && i <= 31)) {
				return true;
			}
			return false;
		} else {
			return true;
		}
	}

	public static String getRealIp(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
		} else if (ip.length() > 15) {
			String[] ips = ip.split(",");
			for (int index = 0; index < ips.length; index++) {
				String strIp = (String) ips[index];
				if (!("unknown".equalsIgnoreCase(strIp))) {
					ip = strIp;
					break;
				}
			}
		}
		return ip;

	}

	public static String getCookies(String name, HttpServletRequest request) {
		return getCookiesMap(request).get(name);
	}

	public static void setCookies(String name, String value, HttpServletResponse response) {
		setCookies(name, value, 0, false, false, response);
	}

	public static void setCookies(String name, String value, boolean httpOnly, HttpServletResponse response) {
		setCookies(name, value, 0, httpOnly, false, response);
	}

	public static void setCookies(String name, String value, long seconds, HttpServletResponse response) {
		setCookies(name, value, seconds, false, false, response);
	}

	@SuppressWarnings("all")
	public static void setCookies(String name, String value, long seconds, boolean httpOnly, boolean secure,
			HttpServletResponse response) {
		setCookies(name, value, null, seconds, httpOnly, secure, response);
	}

	@SuppressWarnings("all")
	public static void setCookies(String name, String value, String domain, long seconds, boolean httpOnly,
			boolean secure, HttpServletResponse response) {
		setCookies(name, value, domain, null, seconds, httpOnly, secure, response);
	}

	@SuppressWarnings("all")
	public static void setCookies(String name, String value, String domain, String path, long seconds, boolean httpOnly,
			boolean secure, HttpServletResponse response) {
		String str = name + "=" + value;
		if (seconds > 0) {
			str += "; Expires=" + new Date(System.currentTimeMillis() + seconds * 1000).toGMTString();
		}
		if (domain != null) {
			str += "; domain=" + domain;
		}

		if (path != null) {
			str += "; path=" + path;
		}

		if (httpOnly) {
			str += "; HttpOnly";
		}
		if (secure) {
			str += "; Secure";
		}

		if (response.containsHeader("Set-Cookie")) {
			response.addHeader("Set-Cookie", str);
		} else {
			response.setHeader("Set-Cookie", str);
		}
	}

	public static Map<String, String> getCookiesMap(HttpServletRequest request) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : request.getCookies()) {
				map.put(cookie.getName(), cookie.getValue());
			}
		}
		return map;
	}

	public static Map<String, String> getHeaderMap(HttpServletRequest request) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Enumeration<String> en = request.getHeaderNames();
		while (en.hasMoreElements()) {
			String key = en.nextElement();
			map.put(key, request.getHeader(key));
		}
		return map;
	}

	public static void push(HttpServletRequest request, Object o) {
		BeanUtil.pushBean(getParameterMapObject(request), o);
	}

	public static Map<String, Object> getParameterMapObject(HttpServletRequest request) {
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		Enumeration<String> en = request.getParameterNames();
		while (en.hasMoreElements()) {
			String key = en.nextElement();
			map.put(key, request.getParameter(key));
		}
		return map;
	}

	public static Map<String, String> getParameterMap(HttpServletRequest request) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		Enumeration<String> en = request.getParameterNames();
		while (en.hasMoreElements()) {
			String key = en.nextElement();
			map.put(key, request.getParameter(key));
		}
		return map;
	}

	public static void main(String[] args) throws Exception {
		Map<String, String> map = new HashMap<String, String>();
		map.put("A", "B\r\nC");
		map.put("AA", "CC");
		String s = toString(map);
		System.out.println(s);
		System.out.println(toMap(s));
	}

	public static Map<String, String> toMap(String str) {
		Map<String, String> map = new LinkedHashMap<String, String>();
		if (str == null || str.trim().length() == 0)
			return map;
		for (String s : str.trim().split("\\r\\n")) {
			s = s.trim();
			if (s.startsWith("#"))
				continue;
			int pos = s.indexOf("=");
			if (pos == -1)
				continue;
			String key = s.substring(0, pos).trim();
			String value = s.substring(pos + 1).trim().replaceAll(SP, "\r\n");
			map.put(key, value);
		}
		return map;
	}

	public static String toString(Map<String, String> map) {
		StringBuffer sb = new StringBuffer();
		if (map != null && map.size() > 0) {
			for (String key : map.keySet()) {
				sb.append(key + "=" + (map.get(key) == null ? "" : map.get(key).replaceAll("\\r\\n", SP)) + "\r\n");
			}
		}
		return sb.toString();
	}

	public final static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
			}
		} else if (ip.length() > 15) {
			String[] ips = ip.split(",");
			for (int index = 0; index < ips.length; index++) {
				String strIp = (String) ips[index];
				if (!("unknown".equalsIgnoreCase(strIp))) {
					ip = strIp;
					break;
				}
			}
		}
		return ip;
	}

	public static String token(HttpServletRequest request) {
		String token = request.getParameter(TOKEN);
		if (token == null) {
			token = request.getHeader(TOKEN);
		}
		if (token != null) {
			request.setAttribute(TOKEN, token);
			return token;
		}

		if (token == null) {
			Object o = request.getAttribute(TOKEN);
			if (o != null && o instanceof String) {
				token = (String) o;
			}
		}
		if (token == null) {
			HttpSession s = request.getSession(true);
			Object o = s.getAttribute(TOKEN);
			if (o != null && o instanceof String) {
				token = (String) o;
				if (token != null) {
					return token;
				}
			}
		}

		return getCookies(TOKEN, request);
	}

	public static String getToken(HttpServletRequest request, HttpServletResponse response) {
		String token = token(request);
		if (token == null) {
			token = BeanUtil.uuid();
			setCookies(TOKEN, token, true, response);
		} else {
			if (getCookies(TOKEN, request) == null) {
				setCookies(TOKEN, token, true, response);
			}
		}
		return token;
	}

	public static void writeHtml(String text, HttpServletResponse response) {
		writeHtml(text, "UTF-8", response);
	}

	public static void writeHtml(String text, String charset, HttpServletResponse response) {
		response.setCharacterEncoding(charset);
		response.setContentType("text/html;charset=" + charset);
		try {
			PrintWriter out = response.getWriter();
			out.print(text);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void writeJSON(String text, HttpServletResponse response) {
		writeJSON(text, "UTF-8", response);
	}

	public static void writeJSON(String text, String charset, HttpServletResponse response) {
		response.setCharacterEncoding(charset);
		response.setContentType("text/json;charset=" + charset);
		try {
			PrintWriter out = response.getWriter();
			out.print(text);
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void noCache() {
		noCache(WebContext.getResponse());
	}

	public static void noCache(HttpServletResponse response) {
		if (response != null) {
			response.setHeader("Cache-Control", "no-cache");
			response.setHeader("Pragma", "no-cache");
			response.setDateHeader("Expires", -1);
		}
	}

	public static void noCache(Writer out) {
		if (out != null) {
			try {
				out.write("<meta HTTP-EQUIV=\"pragma\" CONTENT=\"no-cache\">");
				out.write("<meta HTTP-EQUIV=\"Cache-Control\" CONTENT=\"no-cache, must-revalidate\">");
				out.write("<meta HTTP-EQUIV=\"expires\" CONTENT=\"0\">");
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}

}
